import axios from 'axios'
import qs from 'qs'
import { message } from 'antd'

import { REFRESH_TO_LOGIN_PAGE_MSG, SHOW_ERR_MSG_PREFIX } from '@/consts/consts'
import { refreshToLoginPage } from '@/utils/utils'
import { getToken } from './token'
import { getCustomServer, getDefaultErrMsg, getPath, IRes, isAppApi } from './utils'

declare module 'axios' {
  interface AxiosRequestConfig {
    /** 隐藏异常消息 */
    $hideErrMsg?: boolean | (($res?: IRes) => boolean)
    /** 额外配置 */
    $extra?: any
    /** @deprecated 请使用 signal */
    cancelToken?: CancelToken
  }
  interface AxiosResponse<T = any> {
    /** response.data.data 的引用 */
    $data: T
  }
}

axios.defaults.paramsSerializer = params => {
  return qs.stringify(params, {
    arrayFormat: 'repeat', // 与后端保持一致
  })
}

/* 添加成功请求拦截器，统一逻辑处理 */
axios.interceptors.request.use(({ ...config }) => {
  if (isAppApi(config) /* 安全防护 */) {
    const token = getToken()

    // 本地无登录态
    if (!token && config.$extra !== 'noAuth') {
      refreshToLoginPage()
      throw new Error(REFRESH_TO_LOGIN_PAGE_MSG) // 转成失败
    }

    const newHeaders = new axios.AxiosHeaders(config.headers)

    // 向 headers 添加登录态 & SourceType
    if (token && config.$extra !== 'noAuth') newHeaders.set(...token)
    newHeaders.set('SourceType', { OMS: 1, TMS: 2 }[$APP] ?? 3)

    // 非生产环境客户端侧允许自定义接口服务，方便后端使用界面调试
    if (import.meta.env.VITE_APP_ENV === 'staging') {
      const prefixName = getPath(config).split('/')[1] || ''
      const customServer = getCustomServer(
        {
          ['omsapi']: 'oms',
          ['tmsapi']: 'tms',
        }[prefixName],
      )
      if (customServer) config = { ...config, baseURL: customServer }
    }

    return { ...config, headers: newHeaders }
  }

  return config
})

/* 先添加成功响应拦截器，统一逻辑处理 */
axios.interceptors.response.use(response => {
  const objData: Partial<IRes> = Object(response.data)
  const { success, errorMessage, data, code } = objData //code中间方案

  // response.data.data 的引用
  response.$data = 'data' in objData ? data : undefined

  // 失败的响应体状态码
  if (!success) {
    throw new axios.AxiosError(
      `${code || errorMessage || getDefaultErrMsg(objData)}`,
      'API',
      response.config,
      response.request,
      response,
    )
  }

  return response
})

/* 后添加失败响应拦截器，统一逻辑处理 */
axios.interceptors.response.use(null, err => {
  if (axios.isCancel(err)) throw err

  // AxiosError
  if (axios.isAxiosError(err)) {
    const objData: Partial<IRes> = Object(err.response?.data)
    const { success, errorMessage, data, code } = objData //code 中间方案 后续删除

    // response.data.data 的引用
    if (err.response) err.response.$data = 'data' in objData ? data : undefined

    // 登录态异常自动跳转登录页，同旧系统。TODO: 后续可能要改造
    if (err.config && (err.status === 401 || err.status === 403 || errorMessage === '登录已过期')) {
      if (isAppApi(err.config) && err.config.$extra !== 'noAuth') {
        refreshToLoginPage()
        throw new Error(REFRESH_TO_LOGIN_PAGE_MSG)
      }
    }

    // 异常消息提示
    const hideMsg = err.config?.$hideErrMsg
    if (!success && (typeof hideMsg === 'function' ? !hideMsg(err.response?.data) : !hideMsg)) {
      message.error(`${code || errorMessage || getDefaultErrMsg(objData)}`)
    }
  }

  // Error
  else if (err instanceof Error) {
    // 自定义异常消息提示
    if (err.message.startsWith(SHOW_ERR_MSG_PREFIX)) {
      const showErrMsg = err.message.slice(SHOW_ERR_MSG_PREFIX.length)
      if (showErrMsg) message.error(showErrMsg, 4)
    }
  }

  throw err
})
